/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.homullus.SkeletonLoaders;

import java.util.ArrayList;
import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.homullus.Bone;
import org.homullus.Quad;
import org.homullus.Shape;
import org.homullus.Skeleton;
import org.homullus.Triangle;
import org.lwjgl.util.vector.Vector3f;

/**
 *
 * @author Gary
 */
public class XMLSkeletonLoader implements ISkeletonLoader
{
    private XPath xpath = null;
    private static XMLSkeletonLoader inst = null;

    /*
    private XMLSkeletonLoader()
    {
    }

    public ISkeletonLoader instance() {
        if (inst == null)
            inst = new XMLSkeletonLoader();
        return inst;
    }*/

    public XMLSkeletonLoader() {
    }

    public Skeleton Load(String filename)
    {
        return LoadSkeleton(filename);
    }
    
    public Skeleton LoadSkeleton(String filename)
    {
        Skeleton skel = new Skeleton();
        Bone root = new Bone();
        root.childBones = new ArrayList<Bone>();
        try
        {
            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = builderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(filename);

            XPathFactory xPathFactory = XPathFactory.newInstance();
            xpath = xPathFactory.newXPath();

            String placement = xpath.evaluate("/root/@positining", doc);
            root.x = 0;
            root.y = 0;
            root.z = 0;
            root.r = Float.parseFloat(xpath.evaluate("/root/@r",doc));
            root.g = Float.parseFloat(xpath.evaluate("/root/@g",doc));
            root.b = Float.parseFloat(xpath.evaluate("/root/@b",doc));
            root.Parent = null;
            root.Name = xpath.evaluate("/root/@name",doc);
            root.editable = (xpath.evaluate("/root/@editable", doc).equalsIgnoreCase("true") ? true : false);
            NodeList subBones = (NodeList)xpath.compile("/root/bone").evaluate(doc, XPathConstants.NODESET);
            
            root.childBones = new ArrayList<Bone>();
            LoadBones(subBones, root, placement.equalsIgnoreCase("relative"));
        }
        catch (Exception e)
        {
            System.out.println("Skeleton load error");
            e.printStackTrace();
        }
        skel.SetRoot(root);
        return skel;
    }

    //private Bone LoadShape()

    private void LoadBones(NodeList list, Bone root, boolean relative) throws Exception
    {
        for(int b = 0; b < list.getLength(); b++)
        {
            Bone tempBone = new Bone();
            Node bone = list.item(b);
            tempBone.x = Float.parseFloat(xpath.evaluate("@x",bone)) + (relative ? root.x : 0);
            tempBone.y = Float.parseFloat(xpath.evaluate("@y",bone)) + (relative ? root.y : 0);
            tempBone.z = Float.parseFloat(xpath.evaluate("@z",bone)) + (relative ? root.z : 0);
            tempBone.r = Float.parseFloat(xpath.evaluate("@r",bone));
            tempBone.g = Float.parseFloat(xpath.evaluate("@g",bone));
            tempBone.b = Float.parseFloat(xpath.evaluate("@b",bone));
            tempBone.Name = xpath.evaluate("@name",bone);
            tempBone.editable = (xpath.evaluate("@editable", bone).equalsIgnoreCase("true") ? true : false);
            tempBone.Parent = root;

            Node shapeCheck = (Node)xpath.compile("shapes").evaluate(bone, XPathConstants.NODE);
            if (shapeCheck != null)
            {
                NodeList shapes = (NodeList)xpath.compile("shapes/shape").evaluate(bone,XPathConstants.NODESET);
                Shape shapeObj = new Shape();
                shapeObj.SetWireframe(true);
                int numofshapes = shapes.getLength();
                for (int s = 0; s < numofshapes; s++)
                {
                    Node shape = shapes.item(s);
                    String type = xpath.evaluate("@type", shape);
                    NodeList points = (NodeList)xpath.evaluate("point", shape, XPathConstants.NODESET);
                    if (type.equalsIgnoreCase("QUAD") && points.getLength() == 4)
                    {
                        Quad quad = new Quad();
                        Node point;
                        String xStr;
                        String yStr;
                        String zStr;
                        float x;
                        float y;
                        float z;
                        int p = 0;

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        quad.setFirstPoint(new Vector3f(x,y,z));

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        quad.setSecondPoint(new Vector3f(x,y,z));

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        quad.setThirdPoint(new Vector3f(x,y,z));

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        quad.setFourthPoint(new Vector3f(x,y,z));


                        shapeObj.AddQuad(quad);
                    }
                    else if(type.equalsIgnoreCase("TRI") && points.getLength() == 3)
                    {
                        Triangle tri = new Triangle();
                        Quad quad = new Quad();
                        Node point;
                        String xStr;
                        String yStr;
                        String zStr;
                        float x;
                        float y;
                        float z;
                        int p = 0;

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        tri.setFirstPoint(new Vector3f(x,y,z));

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        tri.setSecondPoint(new Vector3f(x,y,z));

                        point = points.item(p++); //Get the nod and post increment p
                        xStr = xpath.evaluate("@x", point);
                        x = Float.parseFloat(xStr);
                        yStr = xpath.evaluate("@y", point);
                        y = Float.parseFloat(yStr);
                        zStr = xpath.evaluate("@z", point);
                        z = Float.parseFloat(zStr);
                        tri.setThirdPoint(new Vector3f(x,y,z));

                        shapeObj.AddTriangle(tri);
                    }

                }
                tempBone.shape = shapeObj;
            }
            NodeList subBones = (NodeList)xpath.compile("bone").evaluate(bone, XPathConstants.NODESET);
            if (subBones.getLength() > 0)
            {
                tempBone.childBones = new ArrayList<Bone>();
                LoadBones(subBones, tempBone,relative);
            }
            root.childBones.add(tempBone);
        }
    }

    public String Extenson() {
        return ".xml";
    }

    public String Description() {
        return "Xml Skeleton";
    }




}
